#include "Animator.h"
#include "OgreAnimation.h"
static const float END_WEIGHT = 1.0f;

Animator::Animator(Ogre::Entity *ent)
{
	mSet = ent->getAllAnimationStates();
	fadeTime = 0.0f;
	if(!mSet) return;
	Ogre::AnimationStateIterator it = mSet->getAnimationStateIterator();
	while(it.hasMoreElements())
	{
		Ogre::AnimationState* i = it.getNext();
		i->setLength(i->getLength() - 1.f/24.f);
	}
}

Animator::~Animator(void)
{
}
//fading in an animation and replacing other animations with it
void Animator::playAnimation(const AnimationType type, const Ogre::String &name, const bool loop, const bool overwrite, const float speed, const float pos, const float fadeDuration)
{
	if(mSet)
	{
		if(mSet->hasAnimationState(name))
		{
			Ogre::AnimationState* current = mSet->getAnimationState(name);

			if (type == ANIM_FULL)
			{
				if(!(current == mpCurrentFullAnimation) || !current->getEnabled() || ((!current->getLoop() || !loop) && overwrite))
				{
					this->fadeDuration = fadeDuration;
					if(!current->getEnabled()) current->setWeight(0.0f);
					this->fadeTime = 0.0f;
					current->setLoop(loop);
					current->setTimePosition(pos);
					current->setEnabled(true);
				}

				mpCurrentFullAnimation = current;
				mpCurrentUpperAnimation = 0;
				mpCurrentLowerAnimation = 0;
			}
			else if (type == ANIM_UPPER)
			{
				if(!(current == mpCurrentUpperAnimation) || !current->getEnabled() || ((!current->getLoop() || !loop) && overwrite))
				{
					this->fadeDuration = fadeDuration;
					if(!current->getEnabled()) current->setWeight(0.0f);
					this->fadeTime = 0.0f;
					current->setLoop(loop);
					current->setTimePosition(pos);
					current->setEnabled(true);
				}

				mpCurrentFullAnimation = 0;
				mpCurrentUpperAnimation = current;
			}
			else
			{
				if(!(current == mpCurrentLowerAnimation) || !current->getEnabled() || ((!current->getLoop() || !loop) && overwrite))
				{
					this->fadeDuration = fadeDuration;
					if(!current->getEnabled()) current->setWeight(0.0f);
					this->fadeTime = 0.0f;
					current->setLoop(loop);
					current->setTimePosition(pos);
					current->setEnabled(true);
				}

				mpCurrentFullAnimation = 0;
				mpCurrentLowerAnimation = current;
			}
			
			Ogre::AnimationStateIterator it = mSet->getAnimationStateIterator();

			while(it.hasMoreElements())
			{
				Ogre::AnimationState* i = it.getNext();
				mDataMap[i].startWeight = i->getWeight();
			}
			
			mDataMap[current].speed = speed;
		}
	}
}

//settping the animations and decreasing/increasing their weight
void Animator::stepAnimation(const unsigned long elapsedTime)
{
	if(!mSet) return;
	float time(elapsedTime/1000.0f);
	fadeTime += time;
	float fadeUp;
	if(fadeTime < fadeDuration) fadeUp = fadeTime / fadeDuration;
	else fadeUp = 1.0f;
	float fadeDown = 1.0f - fadeUp;
	//stepping the animations according to their speed
	Ogre::AnimationStateIterator it = mSet->getAnimationStateIterator();

	while(it.hasMoreElements())
	{
		Ogre::AnimationState* i = it.getNext();
		if(i->getEnabled())
		{
			if ((i == mpCurrentFullAnimation) || (i == mpCurrentUpperAnimation) || (i == mpCurrentLowerAnimation))
			{
				i->setWeight(mDataMap[i].startWeight * fadeDown + fadeUp);
			}
			else
			{
				i->setWeight(mDataMap[i].startWeight * fadeDown);
			}
			i->addTime(time * mDataMap[i].speed);
		}
		if(i->getWeight() <= 0.0f)
		{
			i->setEnabled(false);
		}
	}
}

Ogre::String Animator::getCurrentAnimationName(const AnimationType type) const
{
	if (type == ANIM_UPPER)
	{
		if (mpCurrentUpperAnimation)
			return mpCurrentUpperAnimation->getAnimationName();
		return Ogre::String();
	}

	if (type == ANIM_LOWER)
	{
		if (mpCurrentLowerAnimation)
			return mpCurrentLowerAnimation->getAnimationName();
		return Ogre::String();
	}

	if (mpCurrentFullAnimation)
		return mpCurrentFullAnimation->getAnimationName();
	return Ogre::String();
}

Ogre::AnimationState* Animator::getAnimation(const Ogre::String &name)
{
	return mSet->getAnimationState(name);
}

void Animator::resetAnimations(void)
{
	if(mSet)
	{
		Ogre::AnimationStateIterator it = mSet->getAnimationStateIterator();
		while(it.hasMoreElements())
		{
			Ogre::AnimationState* i = it.getNext();
			i->setLength(i->getLength() + 1.f/24.f);
		}
	}
}